package com.smallA.association.service.Impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.smallA.association.bo.Result;
import com.smallA.association.constant.DataConstant;
import com.smallA.association.constant.UserConstant;
import com.smallA.association.mapper.AssociationMapper;
import com.smallA.association.mapper.StudentMapper;
import com.smallA.association.mapper.UserMapper;
import com.smallA.association.pojo.Association;
import com.smallA.association.pojo.Client;
import com.smallA.association.pojo.Student;
import com.smallA.association.service.UserService;
import com.smallA.association.utils.DataUtils;
import com.smallA.association.utils.EmailUtils;
import com.smallA.association.utils.ExportExcel;
import com.smallA.association.vo.RegistrationData;
import net.jodah.expiringmap.ExpirationPolicy;
import net.jodah.expiringmap.ExpiringMap;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 用户操作业务逻辑实现类
 *
 * @author 君未言
 */
@Service("UserService")
public class UserServiceImpl implements UserService {
    private static ExpiringMap<String, String> codeMap;
    private static BCryptPasswordEncoder passwordEncoder;
    private static boolean emailBufferFlag;
    private static Set<String> emailBuffer;

    static {
        // 使用静态代码块初始化codeMap
        codeMap = ExpiringMap.builder()
                .expiration(300, TimeUnit.SECONDS)
                // 设置过期时间
                .variableExpiration().expirationPolicy(ExpirationPolicy.CREATED).build();
        // 开启允许更新时间
        emailBufferFlag = true;
        passwordEncoder = new BCryptPasswordEncoder();
    }

    @Resource
    private UserMapper userMapper;
    @Resource
    private AssociationMapper associationMapper;
    @Resource
    private StudentMapper studentMapper;

    /**
     * 初始化缓冲区
     */
    private void initBuffer() {
        emailBufferFlag = false;
        emailBuffer = new HashSet<>();
        List<Map<String, String>> maps = userMapper.selectAllEmail();
        for (Map<String, String> map : maps) {
            emailBuffer.add(map.get("email"));
            // 将已经注册过的邮箱添加到缓冲区中,c
        }
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        return userMapper.findByName(username);
    }

    @Override
    public Result<String> getCode(String address) {
        if (emailBufferFlag) {
            emailBufferFlag = false;
            // initBuffer();
        }
        // 结果就返回6位验证码即可, 随机数解决
        if (!EmailUtils.isValidEmail(address)) {
            return new Result<String>(DataConstant.MSG_CODE_BAD_REQUEST, DataConstant.MSG_BAD_REQUEST);
        }
        if (emailBuffer.contains(address)) {
            // 如果存在就返回提示说这个已经被注册使用过了
            return new Result<String>(DataConstant.EMAIL_CODE_FAIL, "您使用的邮箱已经被注册了");
        }
        String code = Integer.toString(new Random().nextInt(899999) + 10000);
        // 获取一随机验证码
        if (!EmailUtils.sendEmail(address, "您本次登录的验证码为 " + code + "\n验证码5分钟内有效, 请尽快操作", "社团管理平台", "登录验证码")) {
            // 如果发送失败就返回错误码
            return new Result<String>(DataConstant.EMAIL_CODE_FAIL, DataConstant.MSG_NOT_FOUND);
        }
        codeMap.remove(address);
        // 先移除原来可能有的数据, 再重新发送
        codeMap.put(address, code);
        // 放置对应的数据

        System.out.println("邮箱地址 : " + address + " 的验证码为 : " + code);
        return new Result<String>(null, DataConstant.EMAIL_CODE_SUCCESS);
    }

    @Override
    public Result<String> registeredAssociation(RegistrationData data) {
        if (!(DataUtils.examineStr(data.getCode()) && data.getCode().equals(codeMap.get(data.getEmail())))) {
            // 这里就是校验验证码了
            return new Result<>(DataConstant.REGISTER_FAIL, DataConstant.MSG_BAD_REQUEST);
        }
        if (!DataUtils.examineStr(data.getPassword(), 20) || !(DataUtils.examineStr(data.getAssociationName())) || !(DataUtils.examineStr(data.getPhone()))) {
            // 看看其他数据有没有问题
            return new Result<>(DataConstant.REGISTER_FAIL, DataConstant.MSG_BAD_REQUEST);
        }
        // 这里就调用去注册
        Client user = new Client(0, DataConstant.USER_NAME_ASSOCIATION_HEAD + (new Random().nextInt(899999) + 10000), passwordEncoder.encode(data.getPassword()), null);
        userMapper.insertUser(user);
        user = userMapper.selectUserByUserName(user.getUsername());
        data.setUserId(user.getId());
        userMapper.insertRoleByUserId(user.getId(), UserConstant.ROLE_ASSOCIATION_ID);
        associationMapper.insertAssociationByRegistrationData(data);
        emailBuffer.add(data.getEmail());
        return new Result<>("注册成功, 请等待管理员审核通过\n验证通过时将会通过邮件发送对应登录账号", DataConstant.REGISTER_SUCCESS);
    }

    @Override
    public Result<String> checkUsername(Client client) {
        if(!DataUtils.examineStr(client.getUsername(),30)){
            //看看账号有没有问题
            return new Result<>(DataConstant.MSG_CODE_BAD_REQUEST, DataConstant.MSG_BAD_REQUEST);
        }
        int result = userMapper.updateState(client.getUsername());
        if (result != 1) {
            return new Result<>(DataConstant.MSG_CODE_BAD_REQUEST, DataConstant.MSG_BAD_REQUEST);
        }
        return new Result<>("修改成功");
    }

    @Override
    public Result<Object> updateUserState(List<Association> list) {
        if (list.isEmpty()) {
            return new Result<>(DataConstant.ASSOCIATION_REGISTER_FAIL, DataConstant.MSG_BAD_REQUEST);
        }
        // 这里采取的策略就是只要有一个id查询不到就返回错误
        Map<Integer, String> userMap = new HashMap<>();
        //  List<Integer> userIds = new ArrayList<>();
        // 存放用户id和对应的邮箱
        for (Association a : list) {
            if (!DataUtils.examineNumber(a.getId())) {
                // 看看传入的id有没有问题, 有问题就直接gg
                return new Result<>(DataConstant.ASSOCIATION_REGISTER_FAIL, DataConstant.MSG_BAD_REQUEST);
            }
            Association association = associationMapper.selectById(a.getId());
            if (association == null || !DataUtils.examineNumber(association.getUid()) || !EmailUtils.isValidEmail(association.getAssociationRegisterEmail())) {
                // 这里是对基本数据的校验, 用户id, 邮箱一个不能少
                return new Result<>(DataConstant.ASSOCIATION_REGISTER_FAIL, DataConstant.MSG_BAD_UPDATE);
            }
            userMap.put(association.getUid(), association.getAssociationRegisterEmail());
        }
        for (Map.Entry<Integer, String> iter : userMap.entrySet()) {
            if (userMapper.updateStateById(iter.getKey(), UserConstant.STATE_NORMAL) > 0) {
                if (!EmailUtils.sendEmail(iter.getValue(), "恭喜您, 您在社团管理平台使用本邮箱注册的账号为 : " + userMapper.selectUserById(iter.getKey()).getUsername(), "社团管理平台", "账号注册通知")) {
                    // 如果发送失败, 就将重新更新数据, 更新账号信息为注册中
                    userMapper.updateStateById(iter.getKey(), UserConstant.STATE_REGISTER);
                }
            }
        }
        return new Result<>("操作成功", DataConstant.ASSOCIATION_REGISTER_SUCCESS);
    }

    @Override
    public Result<Object> exportExcel(List<Student> list) {
        if (list.isEmpty()) {
            return new Result<>(DataConstant.EXPORT_EXCEL_FAIL, DataConstant.MSG_BAD_REQUEST);
        }
        List<Student> userList = new ArrayList<>();
        for (Student s : list) {
            if (!DataUtils.examineNumber(s.getId())) {
                // 看看传入的id有没有问题, 有问题就直接gg
                return new Result<>(DataConstant.EXPORT_EXCEL_FAIL, DataConstant.MSG_BAD_REQUEST);
            }
            Student student = studentMapper.selectStudentById(s.getId());
            if (student == null || !DataUtils.examineNumber(student.getId(), (int) student.getStudentNumber(), (int) student.getPhone())
            || !DataUtils.examineStr(student.getCollege()) || !DataUtils.examineStr(student.getName())|| !DataUtils.examineStr(student.getSelection())){
                // 这里是对基本数据的校验
                return new Result<>(DataConstant.EXPORT_EXCEL_FAIL, DataConstant.MSG_BAD_UPDATE);
            }
            if ("1".equals(student.getSex())){
                student.setSex("男");
            }else{
                student.setSex("女");
            }
            userList.add(student);
        }
        ExportExcel<Student> ex = new ExportExcel<>();
        String[] headers = {"id","学号", "姓名","性别","学院", "意向部门","联系方式","邮箱","爱好及自我介绍"};

        try {
            OutputStream out = new FileOutputStream("D://"+System.currentTimeMillis()%1000+"导出表单.xls");
//            OutputStream out = new FileOutputStream("D://123.xls");
            ex.exportExcel(headers, userList, out);
            out.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return new Result<>("操作成功", DataConstant.EXPORT_EXCEL_SUCCESS);
    }


    @Override
    public Result<Object> selectUserByAssociation(Client user, String name) {
        //验证账号信息
        if (user != null && DataUtils.examineNumber(user.getId())){
            Association association = associationMapper.selectByUserId(user.getId());
            JSONObject jsonName = JSON.parseObject(name);
            String name1 = (String) jsonName.get("name");

            //验证查询的社团名称是否存在以及是否是管理员管理的社团
            if (association == null ||!associationMapper.selectByAssName(name1).getUid().equals(user.getId())){
                return new Result<>(DataConstant.MSG_CODE_BAD_REQUEST, DataConstant.MSG_NOT_FOUND);
            }
            //都通过就可以查询
            List<Student> students = studentMapper.selectUserByApply(association.getId());
            return new Result<>(students);
        }
        return new Result<>(DataConstant.MSG_CODE_BAD_REQUEST, DataConstant.MSG_BAD_REQUEST);
    }

    @Override
    public Result<Object> noticeByEmail(List<Student> list, String information) {
        if (list.isEmpty()) {
            return new Result<>(DataConstant.NOTICE_EMAIL_FAIL, DataConstant.MSG_BAD_REQUEST);
        }
        List<Student> userList = new ArrayList();
        for (Student s : list) {
            if (!DataUtils.examineNumber(s.getId())) {
                // 看看传入的id有没有问题, 有问题就直接gg
                return new Result<>(DataConstant.NOTICE_EMAIL_FAIL, DataConstant.MSG_BAD_REQUEST);
            }
            Student student = studentMapper.selectStudentById(s.getId());
            if (student == null || !DataUtils.examineNumber(student.getId(), (int) student.getStudentNumber(), (int) student.getPhone())
                    || !DataUtils.examineStr(student.getCollege()) || !DataUtils.examineStr(student.getName())|| !DataUtils.examineStr(student.getSelection())){
                // 这里是对基本数据的校验
                return new Result<>(DataConstant.NOTICE_EMAIL_FAIL, DataConstant.MSG_BAD_UPDATE);
            }
            if ("1".equals(student.getSex())){
                student.setSex("男");
            }else{
                student.setSex("女");
            }
            userList.add(student);
        }
        for(Student student : userList){
            EmailUtils.sendEmail(student.getEmail(), information ,"社团管理平台", "面试结果通知");
            System.out.println(132);
        }
        return new Result<>("操作成功", DataConstant.NOTICE_EMAIL_SUCCESS);
    }
}
